package com.xayy.health.mgt.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.Method;
import cn.kawins.base.result.CheckResult;
import cn.kawins.base.result.ResultBody;
import cn.kawins.base.utils.BeanUtil;
import cn.kawins.base.utils.CollUtil;
import cn.kawins.base.utils.HttpUtil;
import cn.kawins.mybatis.base.BaseServiceImpl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xayy.health.core.config.param.AlgorithmParam;
import com.xayy.health.core.enums.AlgorithmTypeEnum;
import com.xayy.health.core.enums.SystemModelTypeEnum;
import com.xayy.health.core.enums.TaskInfoStatusEnum;
import com.xayy.health.core.exception.HealthException;
import com.xayy.health.mgt.controller.SatelliteController;
import com.xayy.health.mgt.mapper.TelemetryDataMapper;
import com.xayy.health.mgt.model.*;
import com.xayy.health.mgt.model.dto.DataFeatureDto;
import com.xayy.health.mgt.model.dto.TelemetryDto;
import com.xayy.health.mgt.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zhangxa
 */
@Service
public class DataFeatureServiceImpl extends BaseServiceImpl<TelemetryData> implements DataFeatureService {

    @Autowired
    private TelemetryDataMapper telemetryDataMapper;
    @Autowired
    private AlgorithmParam algorithmParam;
    @Autowired
    private HealthAlgorithmManageService algorithmManageService;
    @Autowired
    private SatelliteNodeService satelliteNodeService;
    @Autowired
    private TaskInfoService taskInfoService;
    @Autowired
    private TaskParamInfoService taskParamInfoService;
    @Autowired
    private SatelliteController satelliteController;


    /**
     * 手动试算
     *
     * @param telemetryDto 入参
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> trial(TelemetryDto telemetryDto, HttpServletRequest request) {
        // 获取遥测参数
        List<TelemetryData> telemetryDataList = selectTelemetryData(telemetryDto);
        if (CollectionUtil.isEmpty(telemetryDataList)) {
            throw new HealthException("参数" + telemetryDto.getParamCode() + "遥测数据为空");
        }
        // 剔野数据
        List<Map<String, Object>> ycList = CollUtil.newArrayList();

        telemetryDataList.stream().forEach(x -> {
            Map<String, Object> map = new HashMap<>(2);
            map.put("time", x.getTime());
            map.put("value", x.getValue());
            if(!telemetryDto.isHasNullValue()&&StringUtils.isEmpty(x.getValue())){
                telemetryDto.setHasNullValue(true);
            }
            ycList.add(map);
        });

        telemetryDto.setTelemetryDataList(telemetryDataList);
        // 调用算法
        List<Object> list = predata(telemetryDto);
        String currentParamCode = telemetryDto.getParamCode();
        // 剔野数据
        List<Map<String, Object>> tyList = CollUtil.newArrayList();
        // 填充数据
        List<Map<String, Object>> tcList = CollUtil.newArrayList();
        // 平滑数据
        List<Map<String, Object>> phList = CollUtil.newArrayList();
        // 中位数据
        List<Map<String, String>> jzList = CollUtil.newArrayList();
        // 剔野值
        List<Map<String, Object>> tiYeList = CollUtil.newArrayList();
        // 填充值
        List<Map<String, Object>> tianChongList = CollUtil.newArrayList();

        Map<String, Object> map2 = new HashMap<>(2);
        if(CollectionUtils.isEmpty(list)){
            map2.put("ycList", ycList);
            map2.put("phList", phList);
            map2.put("tyList", tyList);
            map2.put("tcList", tcList);
            map2.put("jzList", jzList);
            map2.put("tiYeList", tiYeList);
            map2.put("tianChongList", tianChongList);
            return map2;
        }

        for (Object o : list) {
            List<Map<String, List<Map<String, List<Map<String, String>>>>>> dataList = new ArrayList<>();
            if (o instanceof JSONObject) {
                dataList.add((Map<String, List<Map<String, List<Map<String, String>>>>>) o);
            } else {
                dataList.addAll((List<Map<String, List<Map<String, List<Map<String, String>>>>>>) o);
            }
            for (Map<String, List<Map<String, List<Map<String, String>>>>> listMap : dataList) {
                for (String key : listMap.keySet()) {
                    if (key.equals(currentParamCode)) {
                        List<Map<String, List<Map<String, String>>>> data = dataList.get(0).get(currentParamCode);
                        for (Map<String, List<Map<String, String>>> stringMap : data) {
                            // 图表数据组装

                            List<Map<String, String>> tyData = stringMap.get("tyData");
                            if (CollectionUtil.isNotEmpty(tyData)) {
                                for (Map<String, String> tyMap : tyData) {
                                    Map<String, Object> map1 = new HashMap<>(2);
                                    map1.put("time", tyMap.get("time"));
                                    DateTime date1 = DateUtil.parse(tyMap.get("time"), "yyyy-MM-dd HH:mm:ss.SSS");
                                    map1.put("timestamp", date1.getTime());
                                    map1.put("value", tyMap.get("value"));
                                    tyList.add(map1);
                                }
                            }

                            List<Map<String, String>> tcData = stringMap.get("tcData");
                            if (CollectionUtil.isNotEmpty(tcData)) {
                                for (Map<String, String> tcMap : tcData) {
                                    Map<String, Object> map1 = new HashMap<>(2);
                                    map1.put("time", tcMap.get("time"));
                                    map1.put("value", tcMap.get("value"));
                                    tcList.add(map1);
                                }
                            }
                            List<Map<String, String>> phData = stringMap.get("phData");
                            if (CollectionUtil.isNotEmpty(phData)) {
                                for (Map<String, String> phMap : phData) {
                                    Map<String, Object> map1 = new HashMap<>(2);
                                    map1.put("time", phMap.get("time"));
                                    map1.put("value", phMap.get("doubleValue"));
                                    phList.add(map1);
                                }
                            }
                            List<Map<String, String>> jzData = stringMap.get("zjData");
                            if (CollectionUtil.isNotEmpty(jzData)) {
                                for (Map<String, String> jzMap : jzData) {
                                    jzList.add(jzMap);
                                }
                            }

                            List<Map<String, String>> tiYeData = stringMap.get("ty");
                            if (CollectionUtil.isNotEmpty(tiYeData)) {
                                for (Map<String, String> tyMap : tiYeData) {
                                    Map<String, Object> map1 = new HashMap<>(2);
                                    map1.put("time", tyMap.get("time"));
                                    map1.put("value", tyMap.get("value"));
                                    tiYeList.add(map1);
                                }
                            }

                            List<Map<String, String>> tianChongData = stringMap.get("tc");
                            if (CollectionUtil.isNotEmpty(tianChongData)) {
                                for (Map<String, String> tcMap : tianChongData) {
                                    Map<String, Object> map1 = new HashMap<>(2);
                                    map1.put("time", tcMap.get("time"));
                                    map1.put("value", tcMap.get("data"));
                                    tianChongList.add(map1);
                                }
                            }
                        }
                        //补数据
//                        List<String> xlist=new ArrayList<>();
//                        List<Map<String, Object>> ycList2 = CollUtil.newArrayList();
//                        if (!CollectionUtils.isEmpty(ycList)) {
//                            ycList2 = DataFeatureServiceImpl.addDataList(ycList);
//                            for(Object obj:ycList2){
//                                Map<String, Object> oneMap = (Map<String, Object>) obj;
//                                xlist.add(oneMap.get("time").toString());
//                            }
//                            xlist=xlist.stream().distinct().sorted().collect(Collectors.toList());
//                        }

//                        if (!CollectionUtils.isEmpty(ycList2)) {
//                            ycList2 = addNullValue(xlist, ycList2);
//                            map2.put("ycList", ycList2);
//                        } else {
//                            map2.put("ycList", ycList);
//                        }
//                        if (!CollectionUtils.isEmpty(phList)) {
//                            phList = addNullValue(xlist, phList);
//                        }
//                        if (!CollectionUtils.isEmpty(tyList)) {
//                            tyList = addNullValue(xlist, tyList);
//                        }
//                        if (!CollectionUtils.isEmpty(tcList)) {
//                            tcList = addNullValue(xlist, tcList);
//                        }

                        map2.put("ycList", ycList);
                        map2.put("phList", phList);
                        map2.put("tyList", tyList);
                        map2.put("tcList", tcList);
                        map2.put("jzList", jzList);

                        map2.put("tiYeList", tiYeList);
                        map2.put("tianChongList", tianChongList);
                    }
                }
            }
        }
        return map2;
    }

    /**
     * 补充数据
     * @param list  需要补充的数据
     * @return 补充后结果
     */
//    public static List<Map<String, Object>> addDataList(List<Map<String, Object>> list) {
//        List<Map<String, Object>> resList=new ArrayList<>();
//        if (CollUtil.isNotEmpty(list)) {
//            if (list.size() > 1) {
//                for (int i = 0; i < list.size() - 1; i++) {
//                    Map<String, Object> dto = list.get(i);
//                    Map<String, Object> dto2 = list.get(i + 1);
//                    String time1 = dto.get("time").toString();
//                    String time2 = dto2.get("time").toString();
//                    time1= ConvertUtils.formatTime(time1);
//                    time2=ConvertUtils.formatTime(time2);
//                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
//                    LocalDateTime timeFormatter1 = LocalDateTime.parse(time1, formatter);
//                    LocalDateTime timeFormatter2 = LocalDateTime.parse(time2, formatter);
//                    LocalDateTime timeFormatter3 = timeFormatter1.plus(DiagnoseServiceImpl.AMOUNT_TO_ADD, ChronoUnit.MILLIS);
//                    dto.put("time",time1);
//                    resList.add(dto);
//                    if (timeFormatter2.isAfter(timeFormatter3)) {
//                        String startLocalDate = timeFormatter3.toLocalDate() + " " + timeFormatter3.toLocalTime();
//                        if (16 == startLocalDate.length()) {
//                            startLocalDate = startLocalDate + ":00";
//                        }
//                        if (!startLocalDate.contains(".")) {
//                            startLocalDate = startLocalDate + ".000";
//                        }
//                        Map<String, Object> map=new HashMap<>();
//                        map.put("time",startLocalDate);
//                        map.put("value",null);
//                        resList.add(map);
//                    }
//                }
//                Map<String, Object> stringObjectMap = list.get(list.size() - 1);
//                stringObjectMap.put("time",ConvertUtils.formatTime(stringObjectMap.get("time").toString()));
//                stringObjectMap.put("value",stringObjectMap.get("value"));
//                resList.add(stringObjectMap);
//            } else {
//                Map<String, Object> stringObjectMap = list.get(0);
//                stringObjectMap.put("time",ConvertUtils.formatTime(stringObjectMap.get("time").toString()));
//                stringObjectMap.put("value",stringObjectMap.get("value"));
//                resList.add(stringObjectMap);
//            }
//        }
//        return resList;
//    }


    /**
     * 补充数据
     *
     * @param xAxis 横坐标
     * @param list  需要补充的数据
     * @return 补充后结果
     */
//    public   static List<Map<String, Object>> addNullValue(List<String> xAxis, List<Map<String, Object>> list) {
//        List<Map<String, Object>> finalList = new ArrayList<>();
//        if (null != list) {
//            Map<Object, Map<String, Object>> map = new HashMap<>();
//            for (Map<String, Object> oneMap : list) {
//                Object time = oneMap.get("time");
//                map.put(time, oneMap);
//            }
//            for (String xa : xAxis) {
//                if (map.containsKey(xa)) {
//                    finalList.add(map.get(xa));
//                } else {
//                    Map<String, Object> nullData=new HashMap<>();
//                    nullData.put("time",xa);
//                    nullData.put("value",null);
//                    finalList.add(nullData);
//                }
//            }
//
//        }
//
//        return finalList;
//    }

    /**
     * 遥测数据
     *
     * @param dataFeatureDto 入参
     * @return List<TelemetryData>
     */
    @Override
    public List<TelemetryData> getYcList(DataFeatureDto dataFeatureDto) {
        return satelliteNodeService.getYcList(dataFeatureDto);
    }

    /**
     * 剔野数据
     *
     * @param dataFeatureDto 入参
     * @return List<TelemetryData>
     */
    @Override
    public List<TelemetryData> getTyList(DataFeatureDto dataFeatureDto) {
        return telemetryDataMapper.getTyList(dataFeatureDto);
    }

    /**
     * 插入剔野数据
     *
     * @param telemetryData 入参
     */
    @Override
    public void insertTy(List<TelemetryData> telemetryData) {
        telemetryDataMapper.insertTy(telemetryData);
    }

    /**
     * 插入填充数据
     *
     * @param telemetryData 填充数据集合
     */
    @Override
    public void insertTc(List<TelemetryData> telemetryData) {
        telemetryDataMapper.insertTc(telemetryData);
    }

    /**
     * 查询平滑数据
     *
     * @param telemetryData 平滑数据集合
     */
    @Override
    public void insertPh(List<TelemetryData> telemetryData) {
        telemetryDataMapper.insertPh(telemetryData);
    }

    /**
     * 填充数据
     *
     * @param dataFeatureDto 入参
     * @return List<TelemetryData>
     */
    @Override
    public List<TelemetryData> getTcList(DataFeatureDto dataFeatureDto) {
        return telemetryDataMapper.getTcList(dataFeatureDto);
    }

    /**
     * 平滑数据
     *
     * @param dataFeatureDto 入参
     * @return List<TelemetryData>
     */
    @Override
    public List<TelemetryData> getPhList(DataFeatureDto dataFeatureDto) {
        return telemetryDataMapper.getPhList(dataFeatureDto);
    }

    /**
     * 数据预处理算法
     *
     * @param telemetryDto 入参
     * @return List<Object>
     */
    @Override
    public List<Object> predata(TelemetryDto telemetryDto) {

        boolean hasNullValue = telemetryDto.isHasNullValue();

        List<Algorithm> algorithmParams = CollUtil.newArrayList();
        Algorithm ty = null;
        HealthAlgorithmManage tyAlgorithmManage = null;
        if (StrUtil.isNotEmpty(telemetryDto.getTyTag())) {
            if(hasNullValue){
                throw new HealthException("调用剔野算法时数据中存在空值，算法异常......");
            }
            tyAlgorithmManage = algorithmManageService.selectOne(HealthAlgorithmManage.builder()
                    .algorithmType(AlgorithmTypeEnum.TY.getCode()).algorithmCode(telemetryDto.getTyTag()).build());
            ty = Algorithm.builder().name("TY").tag(telemetryDto.getTyTag())
                    .fileName(tyAlgorithmManage.getAlgorithmFileName()).build();
        }

        HealthAlgorithmManage tcAlgorithmManage = null;
        Algorithm tc = null;
        if (StrUtil.isNotEmpty(telemetryDto.getTcTag())) {
            if(hasNullValue){
                throw new HealthException("调用填充算法时数据中存在空值，算法异常......");
            }
            tcAlgorithmManage = algorithmManageService.selectOne(HealthAlgorithmManage.builder()
                    .algorithmType(AlgorithmTypeEnum.TC.getCode()).algorithmCode(telemetryDto.getTcTag()).build());
            tc = Algorithm.builder().name("TC").tag(telemetryDto.getTcTag())
                    .fileName(tcAlgorithmManage.getAlgorithmFileName()).build();
        }
        HealthAlgorithmManage phAlgorithmManage = null;
        Algorithm ph = null;
        if (StrUtil.isNotEmpty(telemetryDto.getPhTag())) {
            if(hasNullValue){
                throw new HealthException("调用平滑算法时数据中存在空值，算法异常......");
            }
            phAlgorithmManage = algorithmManageService.selectOne(HealthAlgorithmManage.builder()
                    .algorithmType(AlgorithmTypeEnum.PH.getCode()).algorithmCode(telemetryDto.getPhTag()).build());
            ph = Algorithm.builder().name("PH").tag(telemetryDto.getPhTag())
                    .fileName(phAlgorithmManage.getAlgorithmFileName()).build();
        }

        if (BeanUtil.isNotEmpty(ty)) {
            algorithmParams.add(ty);
        }
        if (BeanUtil.isNotEmpty(tc)) {
            algorithmParams.add(tc);
        }
        if (BeanUtil.isNotEmpty(ph)) {
            algorithmParams.add(ph);
        }
        if(CollectionUtils.isEmpty(algorithmParams)){
            return new ArrayList<>();
        }
        telemetryDto.setZjAlgorithmList(algorithmParams);
        String url = algorithmParam.predataUrl;

        try {
            HttpResponse postResponse =
                    HttpUtil.createRequest(Method.POST, url).body(JSON.toJSONString(telemetryDto)).execute();
            if (postResponse.getStatus() != HttpStatus.HTTP_OK) {
                throw new HealthException("调用剔野算法结果异常");
            }
            return JSON.parseArray(postResponse.body(), Object.class);

        } catch (Exception e) {
            throw new HealthException("调用剔野算法结果异常");
        }
    }

    /**
     * 获取遥测参数
     *
     * @param telemetryDto 入参
     * @return List<TelemetryData>
     */
    @Override
    public List<TelemetryData> selectTelemetryData(TelemetryDto telemetryDto) {
        List<TelemetryData> telemetryDataArrayList = CollUtil.newArrayList();
        String paramCode = telemetryDto.getParamCode();
        DataFeatureDto dataFeatureDto = new DataFeatureDto();
        dataFeatureDto.setSatelliteCode(telemetryDto.getSatelliteCode());
        dataFeatureDto.setParamCode(paramCode);
        dataFeatureDto.setSatelliteCode(telemetryDto.getSatelliteCode());
        dataFeatureDto.setStartTime(telemetryDto.getStartTime());
        dataFeatureDto.setEndTime(telemetryDto.getEndTime());
        dataFeatureDto.setParamCode(paramCode);
        dataFeatureDto.setTimeInterval(telemetryDto.getTimeInterval());
        List<TelemetryData> telemetryDataList = satelliteNodeService.getYcList(dataFeatureDto);
        telemetryDataArrayList.addAll(telemetryDataList);
        return telemetryDataArrayList;
    }

    /**
     * @param telemetryDto 入参
     * @return CheckResult<Object>
     */
    @Override
    public CheckResult<Object> updateSamplingInterval(TelemetryDto telemetryDto) {
        // 新增任务列表
        TaskInfo taskInfo = Convert.convert(TaskInfo.class, telemetryDto);
        taskInfo.setParams(ArrayUtil.join(telemetryDto.getParamCodes(), ","));
        taskInfo.setEndTime(taskInfo.getStartTime());
        String[] paramCodesArrays = telemetryDto.getParamCodes();
        if (ArrayUtil.isNotEmpty(paramCodesArrays)) {
            ArrayList<String> list = new ArrayList<>();
            for (String str : paramCodesArrays) {
                if (telemetryDto.getSatelliteId() != null && StrUtil.isNotEmpty(str)) {
                    ResultBody paramCodeName = satelliteController.screenParam(telemetryDto.getSatelliteId(), str,null);
                    List<SatelliteParam> satelliteParamList = JSONArray.parseArray(paramCodeName.checkResult().getData(), SatelliteParam.class);
                    if (CollUtil.isNotEmpty(satelliteParamList)) {
                        List<SatelliteParam> satelliteParams = satelliteParamList.stream().filter(item -> item.getTelemetryCode().equals(str)).collect(Collectors.toList());
                        if (CollUtil.isNotEmpty(satelliteParams)) {
                            SatelliteParam satelliteParam = satelliteParams.get(0);
                            String paramCodeNames = satelliteParam.getParamName() + "(" + satelliteParam.getTelemetryCode() + ")";
                            list.add(paramCodeNames);
                        }
                    }
                }
            }
            taskInfo.setParamCodeName(CollUtil.join(list, ","));
        }
        // 记录任务类型
        taskInfo.setType(SystemModelTypeEnum.DATA_PROCESSING.getSystemModelTypeCode());
        taskInfo.setStatus(TaskInfoStatusEnum.RUNNING.getStatusCode());
        // 修改参数在别的任务中的状态为失效
        taskParamInfoService.updateStatus(taskInfo);
        taskInfoService.insert(taskInfo);
        // 新增新的参数和任务关系
        taskParamInfoService.insertInfos(taskInfo);
        return CheckResult.success("任务" + telemetryDto.getName() + "上线成功");
    }

    /**
     * 校验任务名称是否重复
     *
     * @param taskInfo 入参
     * @return 结果日志
     */
    public CheckResult<?> checkName(TaskInfo taskInfo) {
        Example example = new Example(TaskInfo.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("type", taskInfo.getType());
        criteria.andEqualTo("name", taskInfo.getName());
        List<TaskInfo> taskInfos = taskInfoService.selectByExample(example);
        if (CollUtil.isNotEmpty(taskInfos)) {
            return CheckResult.fail("任务名称:" + taskInfo.getName() + "已存在");
        }
        return CheckResult.success();
    }





}
